package com.example.demo.base;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.example.demo.common.ApiResult;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.ParameterizedType;
import java.util.List;

@RestController
public abstract class AbstractBaseController<PO extends BasePO, DTO, QUERY extends BaseQuery>  {

    private Class<PO> poClass;

    private Class<DTO> dtoClass;

    public abstract BaseService<PO> baseService();

    @Autowired
    protected MapperFacade mapperFacade;

    @PostMapping("page")
    public ApiResult<PageInfo<DTO>> page(@RequestBody QUERY query){
        PageInfo<PO> page = selectPage(query);
        PageInfo<DTO> pageResult = new PageInfo<>();
        pageResult.setPageNum(page.getPageNum());
        pageResult.setPageSize(page.getPageSize());
        pageResult.setTotal(page.getTotal());
        pageResult.setHasNextPage(page.isHasNextPage());
        pageResult.setEndRow(page.getEndRow());
        pageResult.setHasPreviousPage(page.isHasPreviousPage());
        pageResult.setIsFirstPage(page.isIsFirstPage());
        pageResult.setIsLastPage(page.isIsLastPage());
        if (page.getList() != null) {
            pageResult.setList(mapperFacade.mapAsList(page.getList(),getDTOClass()));
        }
        return ApiResult.ok(pageResult);
    }

    private PageInfo<PO> selectPage(QUERY query) {
        Page<PO> page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return page.doSelectPageInfo(() -> baseService().list(getPageWrappers(query)));
    }

    protected abstract Wrapper<PO> getPageWrappers(QUERY query);



    @PostMapping("/add")
    public ApiResult<DTO> add(@RequestBody DTO dto) {
        boolean save = baseService().save(mapperFacade.map(dto, getPOClass()));
        return ApiResult.ok(dto);
    }

    @PostMapping("/update/selective")
    public ApiResult<DTO> updateByPrimaryKeySelective(@RequestBody DTO dto) {
        boolean b = this.baseService()
                .updateById(mapperFacade.map(dto, getPOClass()));
        return ApiResult.ok(dto);
    }

    @PostMapping("/update")
    public ApiResult<DTO> update(@RequestBody DTO dto) {
        boolean b = this.baseService()
                .saveOrUpdate(mapperFacade.map(dto, getPOClass()));
        return ApiResult.ok(dto);
    }

    @PostMapping("remove/ids")
    public ApiResult<Void> removeByIds(@RequestBody List<Long> ids){
        boolean b = this.baseService()
                .removeByIds(ids);
        return ApiResult.ok();
    }

    protected Class<PO> getPOClass() {
        if (this.poClass == null) {
            this.poClass = (Class<PO>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return this.poClass;
    }

    protected Class<DTO> getDTOClass() {
        if (this.dtoClass == null) {
            this.dtoClass = (Class<DTO>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        }
        return this.dtoClass;
    }
}
